#!/usr/bin/perl

#
# Takes original (not split) stats file as input
#

use Data::Dumper;
use Getopt::Std;
getopts("DNI:JKS:Y:A:M:F:T:B:") || die "usage: $0 [-DNJK] [-S stretch] [-Y y_div] [-A y_max] [-M misalignment_secs] [-F freg_GHz] [-T fontsize] [-B line_style]\n";

$origin_y = 0.02;
$origin_y_step = 0.11;

$per_sec = 2.35; #1.7GHz, 4G samples.
if (defined($opt_F)) {
	$per_sec = 4.0/$opt_F;
}
$min_y = 0.0;
$max_y = 20000;
if (defined($opt_A))  { $max_y = $opt_A;}
if (!defined($opt_M)) {	$opt_M = 0; }

$global_max_y = 0;
$op_max_y[0] = 0;
$sets = 0;
$op = -1;
$op_opt_M = $opt_M;
while (<STDIN>) {
	my $tmp_set;
	chop($_);
	s/_/\\\\_/g;
	if (!m/^\#/) {
		if (m/^title/) {
			($tmp, $TITLE[$sets]) = split( /=/, $_ );
		} else {
			if (m/^set /) {
				if (m/^set opt([A-Z]*)[ \t]([A-z0-9\. ]*)$/) {
					if ($1 eq "N") {$opt_N = "1"; break;}
					if ($1 eq "D") {$opt_D = "1"; break;}
					if ($1 eq "J") {$opt_J = "1"; break;}
					if ($1 eq "K") {$opt_K = "1"; break;}
					if ($1 eq "S") {$opt_S = $2; break;}
					if ($1 eq "Y") {$opt_Y = $2; break;}
					if ($1 eq "A") {$max_y = $2; break;}
					if ($1 eq "M") {$opt_M = $2; break;}
					if ($1 eq "I") {$opt_I = $2; break;}
					if ($1 eq "F") {$per_sec = 4.0/$2; break;}
					if ($1 eq "T") {$opt_T = $2; break;}
					if ($1 eq "B") {$opt_B = $2; break;}
				} else {
					if (!defined($CUSTOM_CMD[$op + 1])) {
						$CUSTOM_CMD[$op + 1] = [];
					}
					push(@{$CUSTOM_CMD[$op + 1]}, $_);
				}
			} else {
				if ($op != -1 && defined($opt_K) && (m/^OP/ || length($_) == 0)) {
					$ops_this_time = 0;
					for (my $i = 0; $i < $#{@tmp_set} ; $i++) {
						$ops_this_time += $tmp_set[$i];
					}
					$TIMELINE[$sets][$op][0] = (100.0 * $tmp_set[0])/$ops_this_time;
					for (my $i = 1; $i < $#{@tmp_set} ; $i++) {
						#print STDERR " " . $tmp_set[$i];
						$TIMELINE[$sets][$op][$i] = (100.0 * $tmp_set[$i])/$ops_this_time + $TIMELINE[$sets][$op][$i - 1];
					}
					#print STDERR "\n";
				}
				if (length($_) == 0) {
					$sets++;
					$op = -1;
				} else {
					if (m/^OP/) {
						s/^OP\\\\_//;
						$op++;
						if ($sets == 0) { $op_opt_M = $opt_M; }
						if ($sets == 0) { $op_max_y[$op] = 0; }
						$time = 0;
						($OP[$sets][$op], $OP_NUM[$sets][$op], $OP_DELAY[$sets][$op]) = split( / /, $_ );
					} else {
						if ($op_opt_M > 0) {
							$op_opt_M -= $per_sec;
						} else {
							$TIMELINE[$sets][$op][$time] = 0;
							my $ops_this_time = 0;
							if(!m/^-$/) {
								my @tmp = split( / /, $_ );
								for (my $i = 0; $i <= $#{@tmp}; $i++) {
									if (defined($opt_K) && $i + 5 < $#{@tmp}) {
										if ($time == 0) {
											$tmp_set[$i] = $tmp[$i];
										} else {
											$tmp_set[$i] += $tmp[$i];
										}
									} else {
										if (defined($opt_J)) {
											$ops_this_time += $tmp[$i];
											$TIMELINE[$sets][$op][$time] += ($tmp[$i] * (10 * $i - 5));
										} else {
											$TIMELINE[$sets][$op][$time] += $tmp[$i];
										}
									}
								}
								if ($ops_this_time != 0 && defined($opt_J)) {
									$TIMELINE[$sets][$op][$time] = $TIMELINE[$sets][$op][$time]/$ops_this_time;
									
								}
							}
							if (defined($opt_K) && defined($opt_I) && $sets == 0) {
								if ($TIMELINE[$sets][$op][$time] < $opt_I) {
									$TIMELINE[$sets][$op][$time] = $TIMELINE[$sets][$op][$time] - 3.0*$opt_I/4.0;
									if ($TIMELINE[$sets][$op][$time] < 0) {$TIMELINE[$sets][$op][$time] = 10;}
								} else {
									$TIMELINE[$sets][$op][$time] = $TIMELINE[$sets][$op][$time]/2.0;
								}
								for (my $i = 0; $i < $TIMELINE[$sets][$op][$time]/10.0; $i++) { print STDERR " 0"; }
								print STDERR " " . $ops_this_time;
								for (my $i = $TIMELINE[$sets][$op][$time]/10.0; $i < 200 ; $i++) { print STDERR " 0"; }
								print STDERR "\n";
							}
							if ($op_max_y[$sets] < $TIMELINE[$sets][$op][$time]) {
								$op_max_y[$op] = $TIMELINE[$sets][$op][$time];
								if ($global_max_y < $op_max_y[$op]) {
									$global_max_y = $op_max_y[$op];
								}
							}
							$time++;
						}
					}
				}
			}
		}
	}
}
# Handle files with no EOF
if ($sets == 0) { $sets = 1; }

$min_x = 0;
if(defined($opt_K)) {
	$max_x = 1000;#$#{@tmp_set} * 10;
	$max_y = 100;
	print "set ytics 0.0,10\n";
} else {
	$max_x = $#{$TIMELINE[0][0]} * $per_sec;
}

$stretch_y = 1;
if (defined($opt_S)) {
	$stretch_y = $opt_S;
}

$y_div = 1;
if (defined($opt_Y)) {
	$y_div = $opt_Y;
}

if ($global_max_y > $max_y && !defined($opt_D)) {
	print STDERR "WARNING: maximal gnuplot Y scale value exceeded ($global_max_y > $max_y).\n";
}

if (defined($opt_T)) {
	$def_font = " font \"Helvetica,$opt_T\"";
} else {
	$def_font = "";
}

if (defined($opt_B)) {
	$plot_style = " $opt_B";
} else {
	$plot_style = " with lines";
}

print <<"END_GNUPLOT";
#!/usr/local/bin/gnuplot

set term push;
set terminal postscript eps enhanced 'Helvetica' 14;

END_GNUPLOT

$size_y = ($#{$TIMELINE[0]} + 1) * $origin_y_step * $stretch_y + $origin_y_step;
if ($sets > 1) { $size_y += $origin_y_step; }

print <<"END_GNUPLOT";
set size 1.0,$size_y
set origin 0.0,0.0
#set style line 1 lt 1 linewidth 20

#set yrange [$min_y:$max_y]
set xrange [$min_x:$max_x]
#set ytics 1.0,10
#set noborder
set border 11
set grid x
set grid y
set multiplot

END_GNUPLOT

if (!defined($opt_D)) {
	print "set yrange [$min_y:$max_y]\n";
}

#if (defined($opt_K)) {
#	for (my $i = 0; $i <= $#{$TIMELINE[0][$op]}; $i++) {
#		$tmp_set[$TIMELINE[0][0][$i]/10.0] = ;
#	}
#	print "#";
#	for (my $i = 0; $i < 200; $i++) {
#		print " " . $tmp_set[$i];
#	}
#	print "\n";
#}

$tics_x = 250;
if (($max_x - $min_x) < 2000) {	$tics_x = 100; }
if (($max_x - $min_x) < 1000) {	$tics_x = 50; }
if (($max_x - $min_x) < 250) {	$tics_x = 10; }
if (($max_x - $min_x) < 100) {	$tics_x = 5;  }
if (($max_x - $min_x) < 25 ) {	$tics_x = 1;  }

for (my $op = 0; $op <= $#{$TIMELINE[0]}; $op++) {
	print "set size 1.0, ", $origin_y_step * $stretch_y + (0.2 - $origin_y_step), "\n";
	print "set origin 0.0, $origin_y\n";
	print "set label \"", $OP[0][$op];
	if (defined($opt_N)) {
		for (my $s = 0; $s < $sets; $s++) {
			for ($j = 0; "$OP[0][$op]" ne "$OP[$s][$j]" && $j <= $#{$OP[$s]}; $j++){}
			if ($j == $#{$OP[$s]} + 1) {
				print "\\n0";
			} else {
				print "\\n$OP_NUM[$s][$j]";
			}
		}
		print "\" at graph 1.05,", 1.0 - 0.2/$stretch_y, " left font \"Helvetica,14\"\n";
	} else {
		print "\" at graph 0.985,", 0.95 - 0.2/$stretch_y, " right font \"Helvetica,16\"\n";
	}
	#if (defined($opt_D)) { print "set yrange [$min_y:1.1*$op_max_y[$op]]\n"; }
	
	if ($op == 0) {
		for (my $i = $tics_x; $i <= $max_x; $i += $tics_x) {
			if ($i > $min_x) {
				print "set label \'$i\' at graph ", ($i - $min_x)/($max_x - $min_x), ",",-0.15/$stretch_y," center $def_font\n";
			}
		}
		if (defined($opt_K)) {
			print "set label \'Timing error (microseconds)\' at graph 0.5,", -0.5/$stretch_y, " center $def_font\n";
			print "set label \'Fraction of operations (%)\' at graph -0.08,", (1 + $#{$TIMELINE[0]})*0.5, " center rotate $def_font\n";
		} else {
			print "set label \'Time (seconds)\' at graph 0.5,", -0.5/$stretch_y, " center $def_font\n";
			if (defined($opt_J)) {
				print "set label \'Timing error (microseconds)\' at graph -0.09,", (1 + $#{$TIMELINE[0]})*0.5, " center rotate $def_font\n";
			} else {
				print "set label \'Number of operations\' at graph -0.1,", (1 + $#{$TIMELINE[0]})*0.5, " center rotate $def_font\n";
			}
		}
	}
	
	# Create major xtics
	if ($op == $#{$TIMELINE[0]}) {
		print "set border\n";
		print "set xtics mirror (";
	} else {
		print "set xtics nomirror (";	
	}
	for ($j = $tics_x; $j < $max_x - $tics_x; $j += $tics_x) {
		print "\"\" ", $j, ",";
	}
	print "\"\" ", $j, ")\n";
	
	$origin_y += $origin_y_step * $stretch_y;
	
	if ($op == $#{$TIMELINE[0]} && $sets > 1) {
		$key_y = 1.0 + 0.6 / $stretch_y;
		$key_y += ($sets - 2) * (0.2 / $stretch_y);
		print "set key graph 0.93,$key_y\n";
	} else {
		print "set nokey\n";
	}
	
	print join("\n", @{$CUSTOM_CMD[$op]}) . "\n";
	
	print "plot '-' t \"$TITLE[$s]\" $plot_style";
	for (my $s = 1; $s < $sets; $s++) {
		print ", '-' t \"$TITLE[$s]\" $plot_style";
	}
	print "\n";
		
	for (my $s = 0; $s < $sets; $s++) {
		for ($j = 0; "$OP[0][$op]" ne "$OP[$s][$j]" && $j <= $#{$OP[$s]}; $j++){}
		if ($j <= $#{$OP[$s]}) {
			for (my $i = 0; $i <= $#{$TIMELINE[0][$op]}; $i++) {
				my $time = ($i + $min_x) * $per_sec;
				print $time, " ", $TIMELINE[$s][$j][$i]/$y_div, "\n";
			}
		} else {
			print "# no $OP[0][$op] found in the input set $s\n";
		}
		print "e\n";
	}
	print "unset label\n";
};

print "set nomultiplot; set out; set term pop\n";
